var display = require('display');
var keyboard = require('keyboard');
var audio = require('audio');

// I am putting all code in function to optimise, if variables are outside
// functions they are put in global namespace, and it's slower to get
// But if you store too much in one function you can cause stackoverflow
function main() {
  // This is XBM format, you can convert images to this format using:
  // https://www.online-utility.org/image/convert/to/XBM
  // dinoRun: 40x43
  var dinoRunWidth = 40;
  var dinoRunHeight = 43;
  var dinoRunSprite = [
    new Uint8Array([
      0x00, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00,
      0xf0, 0xff, 0xff, 0x00, 0x00, 0xf0, 0xfc, 0xff, 0x00, 0x00, 0xf0, 0xfc,
      0xff, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x00,
      0x00, 0xf0, 0xff, 0xff, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x00, 0x00, 0xf0,
      0xff, 0xff, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x00, 0x00, 0xf0, 0x3f, 0x00,
      0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00,
      0xf0, 0xff, 0x0f, 0x03, 0x00, 0xfc, 0x0f, 0x00, 0x03, 0x00, 0xfc, 0x0f,
      0x00, 0x03, 0x80, 0xff, 0x0f, 0x00, 0x03, 0x80, 0xff, 0x0f, 0x00, 0x0f,
      0xf0, 0xff, 0xff, 0x00, 0x0f, 0xf0, 0xff, 0xff, 0x00, 0x3f, 0xfc, 0xff,
      0xcf, 0x00, 0x3f, 0xfc, 0xff, 0xcf, 0x00, 0xff, 0xff, 0xff, 0x0f, 0x00,
      0xff, 0xff, 0xff, 0x0f, 0x00, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xff, 0xff,
      0xff, 0x0f, 0x00, 0xfc, 0xff, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0xff, 0x03,
      0x00, 0xf0, 0xff, 0xff, 0x03, 0x00, 0xf0, 0xff, 0xff, 0x03, 0x00, 0xc0,
      0xff, 0xff, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x3f,
      0x00, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x3c, 0x3c, 0x00, 0x00,
      0x00, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x3c,
      0x30, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00,
      0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00,
    ]),
    new Uint8Array([
      0x00, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00,
      0xf0, 0xff, 0xff, 0x00, 0x00, 0xf0, 0xfc, 0xff, 0x00, 0x00, 0xf0, 0xfc,
      0xff, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x00,
      0x00, 0xf0, 0xff, 0xff, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x00, 0x00, 0xf0,
      0xff, 0xff, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x00, 0x00, 0xf0, 0x3f, 0x00,
      0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00,
      0xf0, 0xff, 0x0f, 0x03, 0x00, 0xfc, 0x0f, 0x00, 0x03, 0x00, 0xfc, 0x0f,
      0x00, 0x03, 0x80, 0xff, 0x0f, 0x00, 0x03, 0x80, 0xff, 0x0f, 0x00, 0x0f,
      0xf0, 0xff, 0xff, 0x00, 0x0f, 0xf0, 0xff, 0xff, 0x00, 0x3f, 0xfc, 0xff,
      0xcf, 0x00, 0x3f, 0xfc, 0xff, 0xcf, 0x00, 0xff, 0xff, 0xff, 0x0f, 0x00,
      0xff, 0xff, 0xff, 0x0f, 0x00, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xff, 0xff,
      0xff, 0x0f, 0x00, 0xfc, 0xff, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0xff, 0x03,
      0x00, 0xf0, 0xff, 0xff, 0x03, 0x00, 0xf0, 0xff, 0xff, 0x03, 0x00, 0xc0,
      0xff, 0xff, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x3f,
      0x00, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0xfc, 0x30, 0x00, 0x00,
      0x00, 0xfc, 0x30, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x00, 0x00, 0x00, 0x3c,
      0xf0, 0x00, 0x00, 0x00, 0x0c, 0xf0, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00,
      0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
    ]),
  ];
  // dino_duck: 55x26
  var dinoDuckSprite = [
    new Uint8Array([
      0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xe0,
      0xff, 0x1f, 0x3f, 0xc0, 0xff, 0x7f, 0xe0, 0xff, 0x1f, 0x3f, 0xc0, 0xff,
      0x7f, 0xf8, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfe, 0x7f, 0xff,
      0xff, 0xff, 0xff, 0x7f, 0xfe, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff,
      0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xf0, 0xff, 0xff, 0xff,
      0xff, 0xff, 0x7f, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xc0, 0xff,
      0xff, 0xff, 0xff, 0xff, 0x7f, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
      0x00, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
      0x1f, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xe1, 0xff, 0x07, 0x00, 0xfc, 0xff,
      0xff, 0xe1, 0xff, 0x07, 0x00, 0xf0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
      0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x7e, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x1e, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
      0x00, 0x00,
    ]),
    new Uint8Array([
      0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xe0,
      0xff, 0x1f, 0x3f, 0xc0, 0xff, 0x7f, 0xe0, 0xff, 0x1f, 0x3f, 0xc0, 0xff,
      0x7f, 0xf8, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfe, 0x7f, 0xff,
      0xff, 0xff, 0xff, 0x7f, 0xfe, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff,
      0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xf0, 0xff, 0xff, 0xff,
      0xff, 0xff, 0x7f, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xc0, 0xff,
      0xff, 0xff, 0xff, 0xff, 0x7f, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
      0x00, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
      0x1f, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xe1, 0xff, 0x07, 0x00, 0xfc, 0xff,
      0xff, 0xe1, 0xff, 0x07, 0x00, 0xf0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
      0xf0, 0xff, 0x60, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xe1, 0x63, 0x00, 0x00,
      0x00, 0x00, 0xf8, 0xe1, 0xe3, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0xe0,
      0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
      0x00, 0x00,
    ]),
  ];
  // ground: 623x12
  var groundSprite = new Uint8Array([
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00,
    0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
    0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00,
    0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x60,
    0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
    0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00,
    0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x3c,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0c, 0x00, 0x1c,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1e,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x38,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x00,
    0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
    0x03, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x60, 0x00, 0x00, 0x00, 0x80,
    0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  ]);
  var bird1Sprite = new Uint8Array([
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
    0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00,
    0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00,
    0xfc, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0x00, 0x00,
    0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00,
    0x00, 0xf0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x3f, 0x00, 0x00,
    0x00, 0xc0, 0xff, 0xff, 0xff, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x03,
    0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00,
    0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
    0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00,
    0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
  ]);
  var bird2Sprite = new Uint8Array([
    0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00,
    0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00,
    0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00,
    0x00, 0x0f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x3f, 0x00, 0x00, 0x00,
    0xc0, 0x0f, 0xff, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0xff, 0x00, 0x00, 0x00,
    0xf0, 0x3f, 0xff, 0x03, 0x00, 0x00, 0xf0, 0x3f, 0xff, 0x03, 0x00, 0x00,
    0xfc, 0x3f, 0xff, 0x0f, 0x00, 0x00, 0xfc, 0x3f, 0xff, 0x0f, 0x00, 0x00,
    0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00,
    0x00, 0xf0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x3f, 0x00, 0x00,
    0x00, 0xc0, 0xff, 0xff, 0xff, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x03,
    0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00,
    0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00,
    0x00, 0x00, 0xf0, 0xff, 0x03, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x03, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  ]);
  var cactusSmallSprite = new Uint8Array([
    0xc0, 0x01, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x23, 0xe0, 0x73,
    0xe0, 0x73, 0xe0, 0x73, 0xe2, 0x73, 0xe7, 0x73, 0xe7, 0x73, 0xe7, 0x73,
    0xe7, 0x73, 0xe7, 0x73, 0xe7, 0x73, 0xe7, 0x7f, 0xe7, 0x3f, 0xe7, 0x1f,
    0xe7, 0x03, 0xff, 0x03, 0xfe, 0x03, 0xfc, 0x03, 0xe0, 0x03, 0xe0, 0x03,
    0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03,
    0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03,
  ]);
  var cactusBigSprite = new Uint8Array([
    0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00,
    0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x0e, 0x7f, 0x00, 0x1f, 0x7f, 0x00,
    0x1f, 0x7f, 0x00, 0x1f, 0x7f, 0x00, 0x1f, 0x7f, 0x00, 0x1f, 0x7f, 0x38,
    0x1f, 0x7f, 0x7c, 0x1f, 0x7f, 0x7c, 0x1f, 0x7f, 0x7c, 0x1f, 0x7f, 0x7c,
    0x1f, 0x7f, 0x7c, 0x1f, 0x7f, 0x7c, 0x1f, 0x7f, 0x7c, 0x1f, 0x7f, 0x7c,
    0x1f, 0x7f, 0x7c, 0xff, 0x7f, 0x7c, 0xfe, 0x7f, 0x7c, 0xfc, 0x7f, 0x7c,
    0xf8, 0x7f, 0x7c, 0xf0, 0x7f, 0x7c, 0x00, 0x7f, 0x7c, 0x00, 0xff, 0x3f,
    0x00, 0xff, 0x1f, 0x00, 0xff, 0x0f, 0x00, 0xff, 0x07, 0x00, 0x7f, 0x00,
    0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00,
    0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00,
    0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00,
    0x00, 0x7f, 0x00, 0x00, 0x7f, 0x04, 0xd0, 0x7f, 0x00,
  ]);
  // cloud: 46x13
  var cloudSprite = new Uint8Array([
    0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x73, 0x00, 0x00,
    0x00, 0x00, 0x18, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00,
    0x00, 0x00, 0x02, 0x80, 0x07, 0x00, 0x00, 0x00, 0x02, 0x80, 0xfc, 0x00,
    0x00, 0xc0, 0x03, 0x40, 0x80, 0x00, 0x00, 0x60, 0x00, 0x00, 0x80, 0x07,
    0xc0, 0x3f, 0x00, 0x00, 0x00, 0x04, 0x60, 0x00, 0x00, 0x00, 0x00, 0x1c,
    0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x36, 0x02, 0x00, 0x00, 0x00, 0x20,
    0x03, 0xfc, 0xff, 0xff, 0xff, 0x3f,
  ]);
  var obstacles = [
    {
      isAnimated: true,
      spawnsY: [88, 62, 45],
      width: 42,
      height: 36,
      sprites: [bird1Sprite, bird2Sprite],
    },
    {
      isAnimated: false,
      spawnsY: [92],
      width: 15,
      height: 33,
      sprites: [cactusSmallSprite],
    },
    {
      isAnimated: false,
      spawnsY: [78],
      width: 23,
      height: 47,
      sprites: [cactusBigSprite],
    },
  ];
  var black = display.color(0, 0, 0);
  var white = display.color(255, 255, 255);
  var grey = display.color(100, 100, 100);
  var gravity = 700;

  // Dino properties
  var dinoY = 82; // Initial position
  var dinoVelocity = 0;
  var dinoJumpStrength = -350;
  var dinoIsJumping = false;
  var dinoIsDucking = false;

  // Obstacle properties
  var obstacleX = 300; // Start off-screen
  var obstacle = obstacles[1];
  var obstacleY = obstacle.spawnsY[0];

  // Ground properties
  var groundX = 0; // Track ground position
  var groundSpeed = 4; // Speed of ground movement
  var sprite = display.createSprite();

  var deltaTime = 0;
  var nowTime = now();
  var oldTime = nowTime;
  var startTime = nowTime;

  var playPointSound = 0;

  var dayInterval = 700;
  var dayTransitionRange = 10;
  var baseColorValue = 0;
  var baseColorInverted = Math.abs(baseColorValue - 255);

  var displayWidth = display.width();
  var displayHeight = display.height();

  var clouds = [
    { x: random(displayWidth, displayWidth + 100), y: random(0, 50) },
    { x: random(displayWidth + 200, displayWidth + 300), y: random(0, 50) },
    { x: random(displayWidth + 400, displayWidth + 500), y: random(0, 50) }
  ];
  var foreground = black;
  var background = white;

  var score = 0;

  sprite.fill(background);
  sprite.setTextColor(foreground);
  sprite.setTextSize(2);
  sprite.setTextAlign(2);
  keyboard.setLongPress(true);
  while (true) {
    if (keyboard.getPrevPress(true)) {
      break; // Exits the game when a prev button is pressed.
    }

    var selPressed = keyboard.getSelPress(true);
    if (selPressed && !dinoIsJumping && !dinoIsDucking) {
      dinoVelocity = dinoJumpStrength; // Start the jump
      dinoIsJumping = true;
      audio.tone(494, 40, true);
    }

    var nextPressed = keyboard.getNextPress(true) || keyboard.getEscPress(true);
    if (nextPressed && !dinoIsJumping) {
      dinoIsDucking = true;
    }

    if (!nextPressed && dinoIsDucking) {
      dinoIsDucking = false;
    }

    nowTime = now();
    deltaTime = (nowTime - oldTime) / 1000;
    oldTime = nowTime;

    score = Math.floor((nowTime - startTime) / 100);

    if (playPointSound === 0 && score % 100 < 10 && score > 50) {
      playPointSound = 1;
      audio.tone(784, 80, true);
    } else if (playPointSound === 1) {
      audio.tone(784, 220, true);
      playPointSound = 2;
    } else if (score % 100 > 50 && playPointSound === 2) {
      playPointSound = 0;
    }

    // Apply gravity
    dinoVelocity += gravity * deltaTime;
    dinoY += dinoVelocity * deltaTime;

    // Prevent dino from falling below ground
    if (dinoY > 82) {
      dinoY = 82;
      dinoIsJumping = false; // Allow jumping again
      dinoVelocity = 0;
    }

    groundSpeed = 4 + Math.floor(score / 200);
    // Move the ground
    groundX -= groundSpeed;
    if (groundX <= -383) {
      groundX = 0; // Reset position for seamless looping
    }

    // Move the obstacle
    obstacleX -= groundSpeed;
    // Reset obstacle
    if (obstacleX < -obstacle.width) {
      obstacleX = displayWidth + random(0, 100); // Random respawn
      obstacle = obstacles[random(0, 3)];
      obstacleY = obstacle.spawnsY[random(0, obstacle.spawnsY.length)];
    }

    // Move clouds
    for (var i = 0; i < 2; i++) {
      clouds[i].x -= groundSpeed - 2;
      if (clouds[i].x < -46) {
        clouds[i].x = displayWidth + 50;
        clouds[i].y = random(0, 50);
      }
    }

    // Day/night cycle
    var modScore = score % (dayInterval * 2);
    baseColorValue = 0;
    baseColorInverted = 255;
    if (modScore % dayInterval >= dayInterval - dayTransitionRange) {
      baseColorValue = Math.round(
        255 *
          (((modScore % dayInterval) - (dayInterval - dayTransitionRange)) /
            dayTransitionRange)
      );
      baseColorInverted = Math.abs(baseColorValue - 255);
    }
    if (modScore < dayInterval) {
      foreground = display.color(
        baseColorValue,
        baseColorValue,
        baseColorValue
      );
      background = display.color(
        baseColorInverted,
        baseColorInverted,
        baseColorInverted
      );
    } else {
      foreground = display.color(
        baseColorInverted,
        baseColorInverted,
        baseColorInverted
      );
      background = display.color(
        baseColorValue,
        baseColorValue,
        baseColorValue
      );
    }

    // Draw the scene
    sprite.fill(background);
    for (var i = 0; i < 2; i++) {
      sprite.drawXBitmap(clouds[i].x, clouds[i].y, cloudSprite, 46, 13, grey);
    }
    sprite.drawXBitmap(groundX, 118, groundSprite, 623, 12, foreground);
    if ((displayWidth > 240) && ((623 + groundX) < displayWidth)) {
      sprite.drawXBitmap(623 + groundX, 118, groundSprite, 623, 12, foreground);
    }
    sprite.drawXBitmap(
      obstacleX,
      obstacleY,
      obstacle.sprites[
        obstacle.isAnimated ? Math.floor((nowTime % 500) / 250) : 0
      ],
      obstacle.width,
      obstacle.height,
      foreground
    );
    if (dinoIsDucking) {
      sprite.drawXBitmap(
        10,
        dinoY + 17,
        dinoDuckSprite[Math.floor((nowTime % 200) / 100)],
        55,
        26,
        foreground
      );
    } else {
      sprite.drawXBitmap(
        10,
        dinoY,
        dinoRunSprite[Math.floor((nowTime % 200) / 100)],
        dinoRunWidth,
        dinoRunHeight,
        foreground
      );
    }
    sprite.setTextColor(foreground);
    sprite.drawText(score, 235, 5);
    sprite.pushSprite();

    // Collision detection
    if (
      20 < obstacleX + obstacle.width &&
      40 > obstacleX &&
      dinoY + dinoRunHeight - 20 /* dinoBottom */ > obstacleY
    ) {
      // Game over
      if (obstacleY < 78) {
        if (obstacleY < 50) {
          if (!dinoIsJumping) continue;
        } else {
          if (dinoIsDucking) continue;
        }
      }

      audio.tone(60, 100); // 50
      delay(20);
      audio.tone(60, 180); // 90
      display.setTextColor(foreground);
      display.setTextSize(2);
      display.setTextAlign(0);
      display.drawText('GAME OVER', 70, 40);
      delay(500);
      while (!keyboard.getAnyPress()) {
        delay(10);
      }

      obstacleX = displayWidth + 50;
      delay(500);
      startTime = now();
    }
  }
  keyboard.setLongPress(false);
}
main();
